package com.tiny.mirror.service.product.infrastructure.repository;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.tiny.mirror.basic.common.code.CommonStatusCode;
import com.tiny.mirror.basic.db.domain.Aggregate;
import com.tiny.mirror.basic.db.domain.AggregateFactory;
import com.tiny.mirror.basic.web.exception.BusinessException;
import com.tiny.mirror.service.product.domain.DomainFactory;
import com.tiny.mirror.service.product.domain.ability.repository.AbilityRepository;
import com.tiny.mirror.service.product.domain.platform.Platform;
import com.tiny.mirror.service.product.domain.platform.repository.PlatformRepository;
import com.tiny.mirror.service.product.infrastructure.entity.db.PlatformAbilityRelEntity;
import com.tiny.mirror.service.product.infrastructure.entity.db.PlatformEntity;
import com.tiny.mirror.service.product.infrastructure.repository.db.PlatformAbilityRelMapper;
import com.tiny.mirror.service.product.infrastructure.repository.db.PlatformMapper;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Repository;

/**
 * @author: chenhao
 * @description:
 * @date: 2023/8/28
 **/
@Repository
public class PlatformRepositoryImpl implements PlatformRepository {

  @Resource
  private PlatformMapper platformMapper;
  @Resource
  private PlatformAbilityRelMapper platformAbilityRelMapper;
  @Resource
  private AbilityRepository abilityRepository;

  @Override
  public Aggregate<Platform> findById(long id) {
    Platform platform = findPlatformById(id);
    return AggregateFactory.createAggregate(platform);
  }

  @Override
  public Platform findPlatformById(long id) {
    PlatformEntity entity = platformMapper.selectById(id);
    if (Objects.isNull(entity)) {
      throw new BusinessException(CommonStatusCode.DATA_NOT_EXIST.args("platform:" + id));
    }
    Platform platform = DomainFactory.convertToPlatform(entity);
    List<PlatformAbilityRelEntity> relList = platformAbilityRelMapper.selectByPlatformId(id);
    if (CollectionUtils.isNotEmpty(relList)) {
      List<Long> abilityIds = relList.stream().map(r -> r.getAbilityId())
          .collect(Collectors.toList());
      platform.setAbilityList(abilityRepository.findAbilityByIds(abilityIds));
    }
    return platform;
  }

  @Override
  public List<Platform> findPlatformByAppId(long appId) {
    QueryWrapper<PlatformEntity> queryWrapper = new QueryWrapper<>();
    queryWrapper.lambda().in(PlatformEntity::getAppId, appId);
    List<PlatformEntity> list = platformMapper.selectList(queryWrapper);
    if (CollectionUtils.isEmpty(list)) {
      return Collections.emptyList();
    }
    List<Platform> platformList = list.stream().map(l -> DomainFactory.convertToPlatform(l))
        .collect(Collectors.toList());
    for (Platform platform : platformList) {
      List<PlatformAbilityRelEntity> relList
          = platformAbilityRelMapper.selectByPlatformId(platform.getId());
      if (CollectionUtils.isNotEmpty(relList)) {
        List<Long> abilityIds = relList.stream().map(r -> r.getAbilityId())
            .collect(Collectors.toList());
        platform.setAbilityList(abilityRepository.findAbilityByIds(abilityIds));
      }
    }
    return platformList;
  }

  @Override
  public void savePlatformAbility(long id, List<Long> abilityIds) {
    List<Long> addList = Lists.newArrayList();
    List<Long> deleteList = Lists.newArrayList();
    List<PlatformAbilityRelEntity> relList = platformAbilityRelMapper.selectByPlatformId(id);
    if (CollectionUtils.isEmpty(relList)) {
      if (CollectionUtils.isEmpty(abilityIds)) {
        return;
      }
      addList.addAll(abilityIds);
    } else {
      List<Long> relAbilityIds = relList.stream()
          .map(r -> r.getAbilityId()).collect(Collectors.toList());
      if (CollectionUtils.isEmpty(abilityIds)) {
        deleteList.addAll(relAbilityIds);
      } else {
        deleteList.addAll(
            relAbilityIds.stream().filter(r -> !abilityIds.contains(r)).collect(Collectors.toList())
        );
        addList.addAll(
            abilityIds.stream().filter(m -> !relAbilityIds.contains(m)).collect(Collectors.toList())
        );
      }
    }
    for (Long abilityId : addList) {
      PlatformAbilityRelEntity entity = new PlatformAbilityRelEntity();
      entity.setPlatformId(id);
      entity.setAbilityId(abilityId);
      platformAbilityRelMapper.insert(entity);
    }
    for (Long abilityId : deleteList) {
      platformAbilityRelMapper.deleteByPlatformIdAndAbilityId(id, abilityId);
    }
  }
}
